package anno

import (
	"fmt"
	"image"
	"image/draw"
	"image/png"
	"os"
	"path/filepath"
	"strings"
)

const (
	// 每张小图的尺寸
	tileWidth  = 144
	tileHeight = 144
)

var (
	// 方向：东南西北
	directions = []string{"s", "w", "e", "n"} // 东南西北
	// 动作名称（英文）
	actionNames = []string{
		"idle", "walk", "run", "attack",
		"defend", "hit", "item", "death",
	}
)

// TraverseDirectory 遍历指定文件夹以及子目录，查找所有的png文件
func TraverseDirectory(dirPath, exportPath string) error {
	err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error {
		// 处理错误
		if err != nil {
			return err
		}

		// 如果是文件夹并且名字包含 "The shadow"，跳过该文件夹
		if info.IsDir() && strings.Contains(info.Name(), "The shadow") {
			fmt.Printf("Skipping directory: %s\n", path)
			return filepath.SkipDir // 跳过该目录及其子目录
		}

		// 仅处理 PNG 文件
		if !info.IsDir() && strings.ToLower(filepath.Ext(path)) == ".png" {
			// 获取输入文件相对于根目录的相对路径
			relativePath, err := filepath.Rel(dirPath, path)
			if err != nil {
				return fmt.Errorf("failed to get relative path for %s: %v", path, err)
			}

			// 拆分出目录和文件名
			relDir := filepath.Dir(relativePath)
			fileName := strings.TrimSuffix(filepath.Base(relativePath), filepath.Ext(relativePath))

			// 构造输出路径: exportPath + 相对目录 + 文件名（无扩展名）
			outputDir := filepath.Join(exportPath, relDir, fileName)

			// 确保输出目录存在
			if err := os.MkdirAll(outputDir, os.ModePerm); err != nil {
				return fmt.Errorf("failed to create output directory %s: %v", outputDir, err)
			}

			// 调用 SplitImage 函数处理图片，并输出到 exportPath + 相对路径
			if err := SplitImage(path, outputDir); err != nil {
				return fmt.Errorf("failed to split image %s: %v", path, err)
			}

			fmt.Printf("✅ SplitImage %s -> %s\n", path, outputDir)
		}
		return nil
	})

	return err
}

// SplitImage 拆分图片为小图并保存
func SplitImage(inputImagePath, outputDir string) error {
	// 加载输入图片
	img, err := loadImage(inputImagePath)
	if err != nil {
		return fmt.Errorf("Error loading image: %v", err)
	}
	// 检查图片尺寸是否符合要求（至少 576x288）
	if img.Bounds().Dx() < 4*tileWidth || img.Bounds().Dy() < 4*tileHeight {
		fmt.Printf("Skipping image: %s\n", inputImagePath)
		return nil // 忽略掉
	}

	// 创建输出目录
	if err := os.MkdirAll(outputDir, os.ModePerm); err != nil {
		return fmt.Errorf("Error creating output directory: %v", err)
	}

	// 4x2 方阵图片，拆分成每个动作，按方向和帧保存
	for row := 0; row < 2; row++ { // 两行
		for col := 0; col < 4; col++ { // 四列
			actionIndex := row*4 + col
			// 确保不会超出 actionNames 数组的范围
			if actionIndex >= len(actionNames) {
				continue // 如果超出范围，则跳过这个位置
			}
			action := actionNames[actionIndex]

			// 每个动作包含东南西北四个方向的 4 帧动画
			for dirIdx, dir := range directions { // 遍历方向
				// 遍历该方向的 4 帧
				for frame := 0; frame < 4; frame++ { // 遍历每一帧
					// 计算每一帧小图的起始坐标
					// 每个动作占据一个 4x4 的区域，按方向和帧的顺序提取每一帧
					x := col*tileWidth*4 + frame*tileWidth    // 每列的宽度加上每帧的宽度偏移
					y := row*tileHeight*4 + dirIdx*tileHeight // 每行的高度加上方向的偏移

					// 计算每一帧小图的位置
					frameImage := img.SubImage(image.Rect(x, y, x+tileWidth, y+tileHeight)).(*image.RGBA)

					// 保存图片
					if err := saveFrame(frameImage, outputDir, action, dir, frame); err != nil {
						return err
					}
				}

			}
		}
	}

	return nil
}

// loadImage 加载图片并转换为 *image.RGBA
func loadImage(filePath string) (*image.RGBA, error) {
	file, err := os.Open(filePath)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	// 解码图片
	img, _, err := image.Decode(file)
	if err != nil {
		return nil, err
	}

	// 将图片转换为 *image.RGBA 类型
	rgbaImg, ok := img.(*image.RGBA)
	if !ok {
		// 如果不是 RGBA 类型，则将其转换为 RGBA 类型
		rgbaImg = image.NewRGBA(img.Bounds())
		draw.Draw(rgbaImg, img.Bounds(), img, image.Point{}, draw.Over)
	}

	return rgbaImg, nil
}

// saveFrame 保存每一帧的小图
func saveFrame(tile *image.RGBA, outputDir, action, direction string, frame int) error {
	// 拼接文件名：动作_方向_序号.png
	fileName := fmt.Sprintf("%s_%s_%d.png", action, direction, frame)

	// 构建保存路径
	frameFilePath := filepath.Join(outputDir, fileName)
	file, err := os.Create(frameFilePath)
	if err != nil {
		return fmt.Errorf("Error creating file: %v", err)
	}
	defer file.Close()

	// 保存为 PNG 格式
	err = png.Encode(file, tile)
	if err != nil {
		return fmt.Errorf("Error saving PNG: %v", err)
	}
	return nil
}
